package com.yupi.dada.scroring;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.yupi.dada.common.ErrorCode;
import com.yupi.dada.exception.BusinessException;
import com.yupi.dada.manager.AiManager;
import com.yupi.dada.model.dto.question.QuestionAnswerDTO;
import com.yupi.dada.model.dto.question.QuestionContentDTO;
import com.yupi.dada.model.entity.App;
import com.yupi.dada.model.entity.Question;
import com.yupi.dada.model.entity.UserAnswer;
import com.yupi.dada.model.vo.QuestionVO;
import com.yupi.dada.service.QuestionService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * AI 测评类应用评分策略
 */
@ScoringStrategyConfig(appType = 1, scoringStrategy = 1)
public class AiTestScoringStrategy implements ScroingStrategy {

    @Resource
    private QuestionService questionService;

    @Resource
    private AiManager aiManager;

    @Resource
    private RedissonClient redissonClient;

    // 分布式锁的 key
    private static final String AI_ANSWER_LOCK = "AI_ANSWER_LOCK";

    /**
     * AI 评分结果本地缓存
     */
    private final Cache<String, String> answerCacheMap =
            Caffeine.newBuilder().initialCapacity(1024)
                    // 缓存 5 分钟移除
                    .expireAfterAccess(5L, TimeUnit.MINUTES)
                    .build();

    /**
     * AI 评分系统消息
     */
    private static final String AI_TEST_SCORING_SYSTEM_MESSAGE =
            "你是一位专业测评专家，请严格按以下规则处理：\n" +
                    "1. 必须输出严格符合JSON格式的结果，仅包含{\"resultName\":\"评价名称\", \"resultDesc\":\"评价描述\"}\n" +
                    "2. JSON外不允许包含其他文本或代码块标记（如```json）\n" +
                    "3. resultDesc字段内容需满足：\n" +
                    "   - 纯文本格式（禁用Markdown）\n" +
                    "   - 长度控制在200-300字\n" +
                    "   - 分三段描述：优势分析（50%）、不足说明（30%）、改进建议（20%）\n" +
                    "示例输出：\n" +
                    "{\"resultName\":\"逻辑缜密型\", \"resultDesc\":\"优势在于...不足在于...建议...\"}";

    @Override
    public UserAnswer doScore(List<String> choices, App app) throws Exception {
        Long appId = app.getId();
        String jsonStr = JSONUtil.toJsonStr(choices);
        String cacheKey = buildCacheKey(appId, jsonStr);
        String answerJson = answerCacheMap.getIfPresent(cacheKey);
        // 如果有缓存，直接返回
        if (StrUtil.isNotBlank(answerJson)) {
            // 构造返回值，填充答案对象的属性
            UserAnswer userAnswer = JSONUtil.toBean(answerJson, UserAnswer.class);
            userAnswer.setAppId(appId);
            userAnswer.setAppType(app.getAppType());
            userAnswer.setScoringStrategy(app.getScoringStrategy());
            userAnswer.setChoices(jsonStr);
            return userAnswer;
        }

        //定义锁
        RLock lock = redissonClient.getLock(AI_ANSWER_LOCK + cacheKey);

        try {
            //竞争锁
            boolean res = lock.tryLock(3, 15, TimeUnit.SECONDS);
            //没抢到锁,强行返回
            if (!res){
                return null;
            }
            // 抢到锁了，执行后续业务逻辑
            // 1. 根据 id 查询到题目
            Question question = questionService.getOne(
                    Wrappers.lambdaQuery(Question.class).eq(Question::getAppId, appId)
            );
            QuestionVO questionVO = QuestionVO.objToVo(question);
            List<QuestionContentDTO> questionContent = questionVO.getQuestionContent();

            // 2. 调用 AI 获取结果
            String userMessage = getAiTestScoringUserMessage(app, questionContent, choices);
            String result = aiManager.doSyncStableRequest(AI_TEST_SCORING_SYSTEM_MESSAGE, userMessage);

            // 检查 AI 返回的内容是否为空
            if (result == null || result.isEmpty()) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "AI 返回内容为空");
            }

            try {
                // 1. 先解析最外层的JSON
                JSONObject outerJson = JSONUtil.parseObj(result);

                // 2. 获取message.content内容
                JSONObject message = outerJson.getJSONObject("message");
                String content = message.getStr("content");

                // 3. 处理content中的JSON
                content = content.replace("\\", "")
                        .replace("\"{", "{")
                        .replace("}\"", "}")
                        .trim();

                // 4. 解析实际的评分结果JSON
                JSONObject resultJson = JSONUtil.parseObj(content);

                // 5. 构造返回值
                UserAnswer userAnswer = new UserAnswer();
                userAnswer.setAppId(appId);
                userAnswer.setAppType(app.getAppType());
                userAnswer.setScoringStrategy(app.getScoringStrategy());
                userAnswer.setChoices(jsonStr);
                userAnswer.setResultName(resultJson.getStr("resultName"));
                userAnswer.setResultDesc(resultJson.getStr("resultDesc"));

                // 缓存结果
                answerCacheMap.put(cacheKey, JSONUtil.toJsonStr(userAnswer));

                return userAnswer;
            } catch (Exception e) {
                // 更详细的错误日志
                System.err.println("解析AI返回结果失败，原始内容: " + result);
                e.printStackTrace();
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "解析AI返回结果失败: " + e.getMessage());
            }
        } finally {
            if (lock != null && lock.isLocked()) {
                lock.unlock();
            }
        }

    }


    /**
     * AI 评分用户消息封装
     *
     * @param app
     * @param questionContentDTOList
     * @param choices
     * @return
     */
    private String getAiTestScoringUserMessage(App app, List<QuestionContentDTO> questionContentDTOList, List<String> choices) {
        StringBuilder userMessage = new StringBuilder();
        userMessage.append(app.getAppName()).append("\n");
        userMessage.append(app.getAppDesc()).append("\n");
        List<QuestionAnswerDTO> questionAnswerDTOList = new ArrayList<>();
        for (int i = 0; i < questionContentDTOList.size(); i++) {
            QuestionAnswerDTO questionAnswerDTO = new QuestionAnswerDTO();
            questionAnswerDTO.setTitle(questionContentDTOList.get(i).getTitle());
            questionAnswerDTO.setUserAnswer(choices.get(i));
            questionAnswerDTOList.add(questionAnswerDTO);
        }
        userMessage.append(JSONUtil.toJsonStr(questionAnswerDTOList));
        return userMessage.toString();
    }


    /**
     * 构建缓存 key
     *
     * @param appId
     * @param choices
     * @return
     */
    private String buildCacheKey(Long appId, String choices) {
        return DigestUtil.md5Hex(appId + ":" + choices);
    }

}
